import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import threading
import time
import json
import os
import sys

class LiquidCoolerUI:
    def __init__(self, root, serial_manager, protocol_parser, data_logger, config_manager):
        self.root = root
        self.root.title("液冷机通信控制软件")
        self.root.geometry("1400x800")  # 稍微增加高度以容纳更好的布局

        # 设置窗口图标（同时会显示在任务栏）
        self.set_app_icon()

        # 设置中文字体
        self.setup_chinese_font()

        # 初始化组件
        self.serial_manager = serial_manager
        self.protocol_parser = protocol_parser
        self.data_logger = data_logger
        self.config_manager = config_manager

        # 加载配置
        self.config = self.config_manager.load_config()

        # 协议配置
        self.current_protocol = None
        self.protocols_dir = "protocol_configs"
        self.available_protocols = self.load_available_protocols()

        # 通信日志颜色配置
        self.tx_color = "#0072BD"  # 深蓝色 - 发送数据
        self.rx_color = "#D95319"  # 橙红色 - 接收数据
        self.timestamp_color = "#4DBEEE"  # 亮蓝色 - 时间戳

        # 初始化组件，传递日志回调函数
        self.serial_manager.log_callback = self.log_communication

        # 数据存储
        self.register_values = {}  # 存储所有寄存器的当前值
        self.timestamps = []
        self.is_connected = False
        self.is_logging = False
        self.is_auto_refresh = False  # 自动刷新状态
        self.auto_refresh_thread = None  # 自动刷新线程

        # 创建界面
        self.create_widgets()

        # 更新可用串口列表
        self.update_serial_ports()

        # 加载默认协议
        if self.available_protocols:
            self.protocol_var.set(self.available_protocols[0])
            self.load_protocol_config()

        # 居中显示主窗口
        self.center_window(self.root)

    def set_app_icon(self):
        """设置应用程序图标"""
        try:
            icon_path = self.get_resource_path("favicon.ico")
            if os.path.exists(icon_path):
                self.root.iconbitmap(icon_path)
                print(f"图标已设置: {icon_path}")
            else:
                print(f"警告：图标文件未找到: {icon_path}")
        except Exception as e:
            print(f"图标设置失败: {e}")

    def get_resource_path(self, relative_path):
        """
        获取资源文件的绝对路径。
        适用于开发环境和 PyInstaller 打包后的环境。
        """
        # PyInstaller 创建临时文件夹，并将路径存储在 _MEIPASS 中
        if hasattr(sys, '_MEIPASS'):
            # print(f"Running in a PyInstaller bundle. _MEIPASS={sys._MEIPASS}") # 调试信息
            return os.path.join(sys._MEIPASS, relative_path)
        # 在开发环境中，直接使用相对路径
        # print("Running in a normal Python environment.") # 调试信息
        return os.path.join(os.path.abspath("."), relative_path)

    def setup_chinese_font(self):
        """设置中文字体支持"""
        # 尝试设置Tkinter中文字体
        self.chinese_font = None
        # 常见的中文字体列表，按优先级排序
        chinese_fonts = ['Microsoft YaHei', 'SimHei', 'SimSun', 'KaiTi', 'FangSong', 'Arial Unicode MS']

        for font_name in chinese_fonts:
            try:
                # 尝试创建字体对象
                test_font = tk.font.Font(family=font_name, size=10)
                self.chinese_font = font_name
                print(f"使用中文字体: {font_name}")
                break
            except:
                continue

        # 如果没有找到合适的中文字体，使用默认字体
        if self.chinese_font is None:
            self.chinese_font = "TkDefaultFont"
            print("警告: 未找到中文字体，使用默认字体")

    def apply_chinese_font(self, widget):
        """应用中文字体到指定控件"""
        try:
            widget.configure(font=(self.chinese_font, 10))
        except:
            pass  # 忽略字体设置错误

    def center_window(self, window):
        """将窗口居中显示"""
        window.update_idletasks()
        width = window.winfo_width()
        height = window.winfo_height()
        x = (window.winfo_screenwidth() // 2) - (width // 2)
        y = (window.winfo_screenheight() // 2) - (height // 2)
        window.geometry('{}x{}+{}+{}'.format(width, height, x, y))

    def load_available_protocols(self):
        """加载可用的协议配置文件"""
        protocols = []
        if not os.path.exists(self.protocols_dir):
            os.makedirs(self.protocols_dir)
            # 创建默认协议文件
            default_protocol = {
                "name": "默认液冷机协议",
                "description": "标准的Modbus RTU协议配置",
                "registers": {
                    "read_only": [
                        {
                            "address": 30001,
                            "name": "当前温度",
                            "description": "液冷机当前温度值",
                            "unit": "°C",
                            "data_type": "float",
                            "scale": 0.1
                        }
                    ],
                    "read_write": [
                        {
                            "address": 40001,
                            "name": "目标温度",
                            "description": "设定液冷机目标温度",
                            "unit": "°C",
                            "data_type": "float",
                            "scale": 0.1,
                            "min_value": 10,
                            "max_value": 40,
                            "default_value": 20
                        }
                    ]
                }
            }
            with open(os.path.join(self.protocols_dir, "default.json"), "w", encoding="utf-8") as f:
                json.dump(default_protocol, f, ensure_ascii=False, indent=2)
            protocols.append("default.json")
        else:
            for file in os.listdir(self.protocols_dir):
                if file.endswith(".json"):
                    protocols.append(file)

        return protocols

    def load_protocol_config(self):
        """加载选定的协议配置文件"""
        protocol_file = self.protocol_var.get()
        if not protocol_file:
            return

        try:
            with open(os.path.join(self.protocols_dir, protocol_file), "r", encoding="utf-8") as f:
                self.current_protocol = json.load(f)

            # 设置设备地址（如果协议配置中有定义）
            device_address = self.current_protocol.get("device_address", 1)  # 默认为1
            self.protocol_parser.set_device_address(device_address)

            # 更新协议信息显示
            self.protocol_name_var.set(self.current_protocol.get("name", "未知协议"))
            self.protocol_desc_var.set(self.current_protocol.get("description", ""))

            # 清空寄存器表格
            for row in self.ro_table.get_children():
                self.ro_table.delete(row)
            for row in self.rw_table.get_children():
                self.rw_table.delete(row)

            # 填充只读寄存器表格
            registers = self.current_protocol.get("registers", {})
            ro_registers = registers.get("read_only", [])
            for reg in ro_registers:
                address = reg.get("address", "")
                name = reg.get("name", "")
                unit = reg.get("unit", "")
                desc = reg.get("description", "")
                data_type = reg.get("data_type", "")
                default_value = reg.get("default_value", "--")

                # 添加空的时间戳初始值
                self.ro_table.insert("", "end", values=(address, name, default_value, unit, desc, data_type, ""))
                self.register_values[address] = default_value

            # 填充读写寄存器表格
            rw_registers = registers.get("read_write", [])
            for reg in rw_registers:
                address = reg.get("address", "")
                name = reg.get("name", "")
                unit = reg.get("unit", "")
                desc = reg.get("description", "")
                data_type = reg.get("data_type", "")
                default_value = reg.get("default_value", "")

                # 添加空的时间戳初始值
                self.rw_table.insert("", "end", values=(address, name, default_value, unit, desc, data_type, ""))
                self.register_values[address] = default_value

            self.status_msg.set(f"已加载协议: {self.current_protocol.get('name', '未知协议')}")

            # 根据协议类型设置读取策略
            protocol_name = self.current_protocol.get("name", "")
            if "TCL" in protocol_name:
                # 对于TCL协议，使用分组读取策略
                self.read_strategy = "grouped"
            else:
                # 对于其他协议，使用连续读取策略
                self.read_strategy = "continuous"

        except Exception as e:
            messagebox.showerror("错误", f"加载协议配置文件失败: {str(e)}")

    def create_widgets(self):
        # 创建主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))

        # 配置网格权重
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)
        main_frame.columnconfigure(0, weight=1)
        main_frame.columnconfigure(1, weight=1)
        main_frame.rowconfigure(2, weight=1)
        main_frame.rowconfigure(3, weight=1)
        main_frame.rowconfigure(4, weight=1)

        # 顶部控制区域
        top_frame = ttk.Frame(main_frame)
        top_frame.grid(row=0, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=(0, 10))

        # 串口配置区域
        serial_frame = ttk.LabelFrame(top_frame, text="串口配置", padding="10")
        serial_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 5))

        serial_inner_frame = ttk.Frame(serial_frame)
        serial_inner_frame.pack(fill=tk.BOTH, expand=True)

        # 第一行串口配置
        row0 = ttk.Frame(serial_inner_frame)
        row0.pack(fill=tk.X, pady=(0, 5))

        ttk.Label(row0, text="端口:").pack(side=tk.LEFT, padx=(0, 5))
        self.port_var = tk.StringVar()
        self.port_combo = ttk.Combobox(row0, textvariable=self.port_var, width=15, state="readonly")
        self.port_combo.pack(side=tk.LEFT, padx=(0, 15))

        ttk.Label(row0, text="波特率:").pack(side=tk.LEFT, padx=(0, 5))
        self.baudrate_var = tk.StringVar(value="9600")
        baudrate_combo = ttk.Combobox(row0, textvariable=self.baudrate_var,
                                      values=["9600", "19200", "38400", "57600", "115200"],
                                      width=10, state="readonly")
        baudrate_combo.pack(side=tk.LEFT, padx=(0, 15))

        self.refresh_btn = ttk.Button(row0, text="刷新端口", command=self.update_serial_ports)
        self.refresh_btn.pack(side=tk.LEFT, padx=(0, 15))

        self.connect_btn = ttk.Button(row0, text="连接", command=self.toggle_connection, width=8)
        self.connect_btn.pack(side=tk.LEFT)

        # 第二行串口配置
        row1 = ttk.Frame(serial_inner_frame)
        row1.pack(fill=tk.X)

        ttk.Label(row1, text="数据位:").pack(side=tk.LEFT, padx=(0, 5))
        self.databits_var = tk.StringVar(value="8")
        databits_combo = ttk.Combobox(row1, textvariable=self.databits_var,
                                      values=["5", "6", "7", "8"], width=5, state="readonly")
        databits_combo.pack(side=tk.LEFT, padx=(0, 15))

        ttk.Label(row1, text="停止位:").pack(side=tk.LEFT, padx=(0, 5))
        self.stopbits_var = tk.StringVar(value="1")
        stopbits_combo = ttk.Combobox(row1, textvariable=self.stopbits_var,
                                      values=["1", "1.5", "2"], width=5, state="readonly")
        stopbits_combo.pack(side=tk.LEFT, padx=(0, 15))

        ttk.Label(row1, text="校验位:").pack(side=tk.LEFT, padx=(0, 5))
        self.parity_var = tk.StringVar(value="N")
        parity_combo = ttk.Combobox(row1, textvariable=self.parity_var,
                                    values=["N", "E", "O", "S", "M"], width=5, state="readonly")
        parity_combo.pack(side=tk.LEFT)

        # 协议配置区域
        protocol_frame = ttk.LabelFrame(top_frame, text="协议配置", padding="10")
        protocol_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(5, 0))

        protocol_inner_frame = ttk.Frame(protocol_frame)
        protocol_inner_frame.pack(fill=tk.BOTH, expand=True)

        # 协议选择行
        protocol_row1 = ttk.Frame(protocol_inner_frame)
        protocol_row1.pack(fill=tk.X, pady=(0, 10))

        ttk.Label(protocol_row1, text="选择协议:").pack(side=tk.LEFT, padx=(0, 5))
        self.protocol_var = tk.StringVar()
        self.protocol_combo = ttk.Combobox(protocol_row1, textvariable=self.protocol_var,
                                           values=self.available_protocols, width=20, state="readonly")
        self.protocol_combo.pack(side=tk.LEFT, padx=(0, 10))
        self.protocol_combo.bind("<<ComboboxSelected>>", lambda e: self.load_protocol_config())

        ttk.Button(protocol_row1, text="重新加载", command=self.load_protocol_config).pack(side=tk.LEFT)

        # 协议信息行
        protocol_row2 = ttk.Frame(protocol_inner_frame)
        protocol_row2.pack(fill=tk.X, pady=(0, 5))

        ttk.Label(protocol_row2, text="协议名称:").pack(side=tk.LEFT, padx=(0, 5))
        self.protocol_name_var = tk.StringVar(value="未选择协议")
        ttk.Label(protocol_row2, textvariable=self.protocol_name_var, foreground="#007acc").pack(side=tk.LEFT)

        # 协议描述行
        protocol_row3 = ttk.Frame(protocol_inner_frame)
        protocol_row3.pack(fill=tk.X)

        ttk.Label(protocol_row3, text="协议描述:").pack(side=tk.LEFT, padx=(0, 5))
        self.protocol_desc_var = tk.StringVar(value="")
        desc_label = ttk.Label(protocol_row3, textvariable=self.protocol_desc_var, wraplength=300, foreground="#555555")
        desc_label.pack(side=tk.LEFT, fill=tk.X, expand=True)

        # 设备控制区域
        control_frame = ttk.LabelFrame(top_frame, text="设备控制", padding="10")
        control_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(5, 0))

        control_inner_frame = ttk.Frame(control_frame)
        control_inner_frame.pack(fill=tk.BOTH, expand=True)

        # 状态显示
        status_row = ttk.Frame(control_inner_frame)
        status_row.pack(fill=tk.X, pady=(0, 10))

        ttk.Label(status_row, text="设备状态:", font=(self.chinese_font, 10, "bold")).pack(side=tk.LEFT, padx=(0, 5))
        self.status_var = tk.StringVar(value="未连接")
        status_label = ttk.Label(status_row, textvariable=self.status_var, foreground="#d9534f")
        status_label.pack(side=tk.LEFT)

        # 控制按钮
        button_row = ttk.Frame(control_inner_frame)
        button_row.pack(fill=tk.X)

        self.read_all_btn = ttk.Button(button_row, text="读取所有寄存器", command=self.read_all_registers)
        self.read_all_btn.pack(side=tk.LEFT, padx=(0, 5))

        self.auto_refresh_btn = ttk.Button(button_row, text="启动定时刷新", command=self.toggle_auto_refresh)
        self.auto_refresh_btn.pack(side=tk.LEFT, padx=(0, 5))

        self.start_log_btn = ttk.Button(button_row, text="开始记录", command=self.toggle_logging)
        self.start_log_btn.pack(side=tk.LEFT)

        # 在设备控制区域添加第三行按钮
        # 在 button_row 下方添加新的按钮行
        button_row2 = ttk.Frame(control_inner_frame)
        button_row2.pack(fill=tk.X, pady=(5, 0))

        self.power_on_btn = ttk.Button(button_row2, text="一键开机", command=self.power_on)
        self.power_on_btn.pack(side=tk.LEFT, padx=(0, 5))

        self.power_off_btn = ttk.Button(button_row2, text="一键关机", command=self.power_off)
        self.power_off_btn.pack(side=tk.LEFT)

        # 只读寄存器区域
        ro_frame = ttk.LabelFrame(main_frame, text="只读寄存器", padding="10")
        ro_frame.grid(row=2, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=(0, 5))
        ro_frame.columnconfigure(0, weight=1)
        ro_frame.rowconfigure(0, weight=1)

        # 创建表格
        columns = ("address", "name", "value", "unit", "description", "data_type", "timestamp")
        self.ro_table = ttk.Treeview(ro_frame, columns=columns, show="headings", height=8)

        # 设置列宽和标题
        col_widths = {"address": 80, "name": 120, "value": 100, "unit": 60,
                      "description": 200, "data_type": 80, "timestamp": 150}

        self.ro_table.heading("address", text="地址")
        self.ro_table.heading("name", text="名称")
        self.ro_table.heading("value", text="当前值")
        self.ro_table.heading("unit", text="单位")
        self.ro_table.heading("description", text="描述 (点击查看详情)")
        self.ro_table.heading("data_type", text="数据类型")
        self.ro_table.heading("timestamp", text="更新时间")

        for col, width in col_widths.items():
            self.ro_table.column(col, width=width, minwidth=width)

        # 添加滚动条
        ro_scrollbar = ttk.Scrollbar(ro_frame, orient=tk.VERTICAL, command=self.ro_table.yview)
        self.ro_table.configure(yscrollcommand=ro_scrollbar.set)

        # 布局表格和滚动条
        self.ro_table.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        ro_scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S))

        # 为只读寄存器表格添加点击事件
        self.ro_table.bind('<ButtonRelease-1>', lambda e: self.on_table_click(e, self.ro_table))

        # 读写寄存器区域
        rw_frame = ttk.LabelFrame(main_frame, text="读写寄存器", padding="10")
        rw_frame.grid(row=3, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=(0, 5))
        rw_frame.columnconfigure(0, weight=1)
        rw_frame.rowconfigure(0, weight=1)

        self.rw_table = ttk.Treeview(rw_frame, columns=columns, show="headings", height=8)

        self.rw_table.heading("address", text="地址")
        self.rw_table.heading("name", text="名称")
        self.rw_table.heading("value", text="当前值")
        self.rw_table.heading("unit", text="单位")
        self.rw_table.heading("description", text="描述 (点击查看详情)")
        self.rw_table.heading("data_type", text="数据类型")
        self.rw_table.heading("timestamp", text="更新时间")

        for col, width in col_widths.items():
            self.rw_table.column(col, width=width, minwidth=width)

        rw_scrollbar = ttk.Scrollbar(rw_frame, orient=tk.VERTICAL, command=self.rw_table.yview)
        self.rw_table.configure(yscrollcommand=rw_scrollbar.set)

        self.rw_table.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        rw_scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S))

        # 为读写寄存器表格添加双击事件
        self.rw_table.bind("<Double-1>", self.on_rw_table_double_click)

        # 为读写寄存器表格添加点击事件
        self.rw_table.bind('<ButtonRelease-1>', lambda e: self.on_table_click(e, self.rw_table))

        # 通信日志区域
        log_frame = ttk.LabelFrame(main_frame, text="通信日志", padding="10")
        log_frame.grid(row=4, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S))
        log_frame.columnconfigure(0, weight=1)
        log_frame.rowconfigure(0, weight=1)

        # 创建通信日志文本框和滚动条
        self.comm_log = tk.Text(log_frame, height=8, wrap=tk.WORD, state=tk.DISABLED, bg="#f8f9fa")
        comm_scrollbar = ttk.Scrollbar(log_frame, orient=tk.VERTICAL, command=self.comm_log.yview)
        self.comm_log.configure(yscrollcommand=comm_scrollbar.set)

        self.comm_log.tag_configure("timestamp", foreground=self.timestamp_color, font=(self.chinese_font, 9, "bold"))
        self.comm_log.tag_configure("tx", foreground=self.tx_color, font=(self.chinese_font, 9))
        self.comm_log.tag_configure("rx", foreground=self.rx_color, font=(self.chinese_font, 9))

        # 日志按钮框架
        log_button_frame = ttk.Frame(log_frame)
        log_button_frame.grid(row=1, column=0, columnspan=2, sticky=(tk.E), pady=(5, 0))

        # 添加清空日志按钮
        clear_log_btn = ttk.Button(log_button_frame, text="清空日志", command=self.clear_communication_log)
        clear_log_btn.pack(side=tk.RIGHT, padx=(5, 0))

        # 新增：保存日志按钮
        self.save_log_btn = ttk.Button(log_button_frame, text="保存日志", command=self.save_communication_log)
        self.save_log_btn.pack(side=tk.RIGHT, padx=(5, 0))

        # 布局日志区域
        self.comm_log.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        comm_scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S))

        # 状态栏
        status_frame = ttk.Frame(main_frame, relief=tk.SUNKEN)
        status_frame.grid(row=5, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=(5, 0))

        self.status_msg = tk.StringVar(value="就绪")
        status_label = ttk.Label(status_frame, textvariable=self.status_msg, foreground="#007acc")
        status_label.pack(side=tk.LEFT, padx=10)

        # 绑定关闭事件
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)

        # 应用字体
        self.apply_chinese_font(self.ro_table)
        self.apply_chinese_font(self.rw_table)
        self.apply_chinese_font(self.comm_log)

    # 以下所有方法保持不变，只修改了布局部分
    # ... [所有其他方法保持不变，为了节省空间省略了重复代码]
    # 注意：这里应该包含所有原有的方法，只是不重复显示

    # 添加电源控制方法
    def power_on(self):
        """一键开机"""
        if not self.is_connected:
            messagebox.showerror("错误", "请先连接设备")
            return

        if not self.current_protocol:
            messagebox.showerror("错误", "请先加载协议配置")
            return

        protocol_name = self.current_protocol.get("name", "")

        try:
            if "tf" in protocol_name:
                # 同飞液冷机开机流程
                # 1. 设置工作模式为制冷 (地址4097, 值1)
                self.send_register_value(4096, 1, "uint16")
                # 1. 设置工作模式为制冷 (地址4097, 值1)
                self.send_register_value(4097, 1, "uint16")
                # 2. 设置制冷预设温度为18℃ (地址4099, 值18)
                self.send_register_value(4099, 18, "uint16")

                self.status_msg.set("同飞液冷机已开机，工作模式设置为制冷，温度设置为18℃")

            elif "tcl" in protocol_name:
                # TCL液冷机开机流程
                # 1. 开机 (地址45056, 值1)
                self.send_register_value(45056, 1, "uint16")
                # 2. 设置工作模式为监控模式 (地址45064, 值2)
                self.send_register_value(45064, 2, "uint16")
                # 3. 设置监控模式&监控温度为制冷 (地址45079, 值1)
                self.send_register_value(45079, 1, "uint16")

                self.status_msg.set("TCL液冷机已开机，工作模式为监控模式，监控温度为制冷")
            else:
                messagebox.showinfo("提示", "当前协议不支持一键开机功能")

        except Exception as e:
            messagebox.showerror("错误", f"开机命令发送失败: {str(e)}")

    def power_off(self):
        """一键关机"""
        if not self.is_connected:
            messagebox.showerror("错误", "请先连接设备")
            return

        if not self.current_protocol:
            messagebox.showerror("错误", "请先加载协议配置")
            return

        protocol_name = self.current_protocol.get("name", "")

        try:
            if "tf" in protocol_name:
                # 同飞液冷机关机流程
                # 设置工作模式为待机 (地址4097, 值0)
                self.send_register_value(4097, 0, "uint16")

                self.status_msg.set("同飞液冷机已关机")

            elif "tcl" in protocol_name:
                # TCL液冷机关机流程
                # 1. 关机 (地址45056, 值0)
                self.send_register_value(45056, 0, "uint16")
                # 2. 设置监控模式&监控温度为关机 (地址45079, 值0)
                self.send_register_value(45079, 0, "uint16")

                self.status_msg.set("TCL液冷机已关机")
            else:
                messagebox.showinfo("提示", "当前协议不支持一键关机功能")

        except Exception as e:
            messagebox.showerror("错误", f"关机命令发送失败: {str(e)}")

    def toggle_auto_refresh(self):
        """切换自动刷新状态"""
        if self.is_auto_refresh:
            self.stop_auto_refresh()
        else:
            self.start_auto_refresh()

    def start_auto_refresh(self):
        """启动自动刷新"""
        if not self.is_connected:
            messagebox.showerror("错误", "请先连接设备")
            return

        self.is_auto_refresh = True
        self.auto_refresh_btn.config(text="停止定时刷新")
        self.status_msg.set("已启动定时刷新")

        # 启动自动刷新线程
        self.auto_refresh_thread = threading.Thread(target=self.auto_refresh_loop, daemon=True)
        self.auto_refresh_thread.start()

    def stop_auto_refresh(self):
        """停止自动刷新"""
        self.is_auto_refresh = False
        self.auto_refresh_btn.config(text="启动定时刷新")
        self.status_msg.set("已停止定时刷新")

    def auto_refresh_loop(self):
        """自动刷新循环"""
        while self.is_auto_refresh and self.is_connected:
            try:
                # 读取所有寄存器
                self.read_all_registers()
                time.sleep(2)  # 每2秒刷新一次（根据协议复杂度调整）
            except Exception as e:
                self.status_msg.set(f"自动刷新错误: {str(e)}")
                time.sleep(1)

    def on_table_click(self, event, table):
        """处理表格点击事件，用于显示描述详情"""
        # 获取点击的区域
        region = table.identify_region(event.x, event.y)

        # 如果是单元格点击
        if region == "cell":
            # 获取点击的列
            column = table.identify_column(event.x)

            # 如果是描述列（第5列）
            if column == "#5":
                # 获取点击的行
                row = table.identify_row(event.y)

                # 获取行数据
                item = table.item(row)
                values = item['values']

                # 获取描述内容
                description = values[4] if len(values) > 4 else ""

                # 显示描述详情
                if description:
                    self.show_description_dialog(description)

    def log_communication(self, direction, data):
        """记录通信数据到日志，使用不同颜色区分Tx和Rx，长数据换行时与数据开头对齐"""
        from datetime import datetime
        timestamp = datetime.now().strftime("%H:%M:%S.%f")[:-3]  # 格式: 10:55:33.294

        # 使用新函数格式化数据
        hex_data = self.format_bytes(data)

        # 确定颜色和方向文本
        if direction == "Tx":
            color = self.tx_color
            direction_text = "发送"
            tag_name = "tx"
        else:
            color = self.rx_color
            direction_text = "接收"
            tag_name = "rx"

        # 计算第一行前缀的长度（时间戳 + 方向文本 + 冒号和空格）
        prefix = f"{timestamp} {direction_text}: "
        prefix_length = len(prefix)

        # 如果数据太长需要换行，创建带缩进的格式
        max_line_length = 80  # 每行最大字符数
        formatted_lines = []

        # 分割长数据为多行
        remaining_data = hex_data
        first_line = True

        while remaining_data:
            if first_line:
                # 第一行包含前缀
                available_length = max_line_length - prefix_length
                if len(remaining_data) <= available_length:
                    formatted_lines.append(prefix + remaining_data)
                    break
                else:
                    # 找到合适的断点
                    break_pos = available_length
                    while break_pos > 0 and remaining_data[break_pos] not in (' ', ',', ':', ';'):
                        break_pos -= 1

                    if break_pos == 0:  # 没有找到合适的断点
                        break_pos = available_length

                    formatted_lines.append(prefix + remaining_data[:break_pos])
                    remaining_data = remaining_data[break_pos:].lstrip()
                    first_line = False
            else:
                # 后续行使用空格缩进，与第一行数据开头对齐
                indent = " " * prefix_length
                available_length = max_line_length - prefix_length

                if len(remaining_data) <= available_length:
                    formatted_lines.append(indent + remaining_data)
                    break
                else:
                    # 找到合适的断点
                    break_pos = available_length
                    while break_pos > 0 and remaining_data[break_pos] not in (' ', ',', ':', ';'):
                        break_pos -= 1

                    if break_pos == 0:  # 没有找到合适的断点
                        break_pos = available_length

                    formatted_lines.append(indent + remaining_data[:break_pos])
                    remaining_data = remaining_data[break_pos:].lstrip()

        formatted_text = "\n".join(formatted_lines)

        # 获取当前滚动位置
        scroll_position = self.comm_log.yview()

        self.comm_log.configure(state=tk.NORMAL)

        if first_line:  # 如果只有一行
            # 插入时间戳（使用时间戳颜色）
            self.comm_log.insert(tk.END, timestamp + " ", "timestamp")
            # 插入方向和数据（使用Tx/Rx颜色）
            self.comm_log.insert(tk.END, f"{direction_text}: {hex_data}\n", tag_name)
        else:
            # 对于多行文本，直接插入格式化后的文本
            self.comm_log.insert(tk.END, formatted_text + "\n", tag_name)

        # 恢复滚动位置并滚动到底部
        self.comm_log.see(tk.END)
        self.comm_log.configure(state=tk.DISABLED)

        # 配置标签样式
        self.comm_log.tag_configure("timestamp", foreground=self.timestamp_color)
        self.comm_log.tag_configure("tx", foreground=self.tx_color)
        self.comm_log.tag_configure("rx", foreground=self.rx_color)

    def clear_communication_log(self):
        """清空通信日志"""
        self.comm_log.configure(state=tk.NORMAL)
        self.comm_log.delete(1.0, tk.END)
        self.comm_log.configure(state=tk.DISABLED)

    def save_communication_log(self):
        """将通信日志保存到文件"""
        # 获取文本内容
        self.comm_log.configure(state=tk.NORMAL)
        log_content = self.comm_log.get(1.0, tk.END).strip()
        self.comm_log.configure(state=tk.DISABLED)

        if not log_content:
            messagebox.showinfo("提示", "日志为空，无需保存。")
            return

        # 弹出文件保存对话框
        file_path = filedialog.asksaveasfilename(
            title="保存通信日志",
            defaultextension=".txt",
            filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
        )

        if not file_path:
            return  # 用户取消了保存

        try:
            with open(file_path, 'w', encoding='utf-8') as f:
                f.write(log_content)
            self.status_msg.set(f"日志已保存至: {file_path}")
            messagebox.showinfo("成功", f"日志已成功保存到\n{file_path}")

        except Exception as e:
            messagebox.showerror("保存失败", f"无法保存日志文件:\n{str(e)}")

    def show_description_dialog(self, description):
        """显示描述详情的对话框"""
        dialog = tk.Toplevel(self.root)
        dialog.title("描述详情")
        dialog.geometry("600x400")
        dialog.transient(self.root)
        dialog.grab_set()

        # 创建文本框和滚动条
        text_frame = ttk.Frame(dialog, padding="10")
        text_frame.pack(fill=tk.BOTH, expand=True)

        text_widget = tk.Text(text_frame, wrap=tk.WORD, font=(self.chinese_font, 10))
        text_widget.insert(tk.END, description)
        text_widget.config(state=tk.DISABLED)  # 设置为只读

        scrollbar = ttk.Scrollbar(text_frame, orient=tk.VERTICAL, command=text_widget.yview)
        text_widget.configure(yscrollcommand=scrollbar.set)

        text_widget.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

        # 添加关闭按钮
        button_frame = ttk.Frame(dialog)
        button_frame.pack(pady=10)

        ttk.Button(button_frame, text="关闭", command=dialog.destroy).pack()

        # 居中显示对话框
        self.center_window(dialog)

    def on_rw_table_double_click(self, event):
        """处理读写寄存器表格的双击事件"""
        item = self.rw_table.selection()[0]
        values = self.rw_table.item(item, "values")
        address = values[0]
        name = values[1]
        current_value = values[2]
        unit = values[3]
        data_type = values[5]

        # 获取寄存器的配置信息
        reg_config = None
        if self.current_protocol:
            for reg in self.current_protocol.get("registers", {}).get("read_write", []):
                if str(reg.get("address", "")) == address:
                    reg_config = reg
                    break

        # 创建设置对话框
        self.create_setting_dialog(address, name, current_value, unit, data_type, reg_config)

    def create_setting_dialog(self, address, name, current_value, unit, data_type, reg_config):
        """创建设置寄存器值的对话框"""
        dialog = tk.Toplevel(self.root)
        dialog.title(f"设置 {name}")
        dialog.geometry("400x200")
        dialog.transient(self.root)
        dialog.grab_set()

        value_frame = ttk.Frame(dialog)
        value_frame.pack(pady=10)

        ttk.Label(dialog, text=f"寄存器: {name} ({address})").pack(pady=10)

        ttk.Label(value_frame, text="值:").grid(row=0, column=0, padx=5)
        value_var = tk.StringVar(value=current_value)
        value_entry = ttk.Entry(value_frame, textvariable=value_var, width=15)
        value_entry.grid(row=0, column=1, padx=5)

        if unit:
            ttk.Label(value_frame, text=unit).grid(row=0, column=2, padx=5)

        # 添加范围提示
        if reg_config:
            min_val = reg_config.get("min_value")
            max_val = reg_config.get("max_value")
            if min_val is not None and max_val is not None:
                ttk.Label(dialog, text=f"取值范围: {min_val} - {max_val}").pack(pady=5)

        button_frame = ttk.Frame(dialog)
        button_frame.pack(pady=20)

        def set_value():
            try:
                new_value = value_var.get()
                # 验证数值范围
                if reg_config:
                    min_val = reg_config.get("min_value")
                    max_val = reg_config.get("max_value")
                    if min_val is not None and max_val is not None:
                        num_value = float(new_value)
                        if num_value < min_val or num_value > max_val:
                            messagebox.showerror("错误", f"值必须在 {min_val} 到 {max_val} 之间")
                            return

                # 更新表格显示
                for item in self.rw_table.get_children():
                    if self.rw_table.item(item, "values")[0] == address:
                        self.rw_table.set(item, "value", new_value)
                        break

                # 更新内部存储
                self.register_values[address] = new_value

                # 发送到设备
                if self.is_connected:
                    self.send_register_value(address, new_value, data_type)

                dialog.destroy()

            except ValueError:
                messagebox.showerror("错误", "请输入有效的数值")

        ttk.Button(button_frame, text="设置", command=set_value).pack(side=tk.LEFT, padx=10)
        ttk.Button(button_frame, text="取消", command=dialog.destroy).pack(side=tk.LEFT, padx=10)

        # 居中显示对话框
        self.center_window(dialog)

    @staticmethod
    def format_bytes(data):
        """
        将 bytes 或 bytearray 格式化为十六进制字符串，例如 "01 03 00 00 00 05 C8 38"
        """
        if isinstance(data, (bytes, bytearray)):
            return ' '.join(f'{byte:02X}' for byte in data)
        return str(data)  # 如果不是字节类型，直接转换为字符串

    def send_register_value(self, address, value, data_type):
        """发送寄存器值到设备 - HEX格式"""
        try:
            # 查找寄存器配置以获取缩放因子
            reg_config = None
            if self.current_protocol:
                for reg in self.current_protocol.get("registers", {}).get("read_write", []):
                    if str(reg.get("address")) == address:
                        reg_config = reg
                        break

            scale = reg_config.get("scale", 1) if reg_config else 1

            # 根据数据类型转换值并进行单位换算
            if data_type == "float":
                # 对于浮点数，应用单位换算 (发送时除以缩放因子)
                num_value = float(value) / scale
                # 转换为整数表示（根据设备要求）
                num_value = int(round(num_value))
            elif data_type == "uint16":
                # 无符号16位整数，应用单位换算
                num_value = int(float(value) / scale)
            elif data_type == "int16":
                # 有符号16位整数，应用单位换算
                num_value = int(float(value) / scale)
                # 处理负数（如果需要）
                if num_value < 0:
                    num_value = 65536 + num_value  # 转换为无符号表示
            else:
                num_value = int(float(value) / scale)  # 默认处理

            # 创建HEX格式的命令
            hex_command = self.protocol_parser.format_hex_command("WRITE_SINGLE_REGISTER", address, num_value)

            if hex_command:
                # 发送HEX命令
                self.serial_manager.serial_port.write(hex_command)
                self.status_msg.set(f"已发送HEX命令到寄存器 {address}")

                # 记录发送的HEX数据
                if hasattr(self, 'log_communication'):
                    self.log_communication("Tx", hex_command)

                # 等待一段时间后读取更新后的值
                self.root.after(100, self.read_all_registers)
            else:
                self.status_msg.set("无法创建HEX命令")

        except ValueError:
            messagebox.showerror("错误", "无效的数值格式")
        except Exception as e:
            messagebox.showerror("错误", f"发送命令失败: {str(e)}")

    def read_all_registers(self):
        """读取所有寄存器的值 - HEX格式"""
        if not self.is_connected:
            messagebox.showerror("错误", "请先连接设备")
            return

        try:
            # 发送读取所有寄存器的命令
            if self.current_protocol:
                # 获取协议名称以确定读取策略
                protocol_name = self.current_protocol.get("name", "")

                # 对于TCL协议，使用分组读取策略
                if "TCL" in protocol_name:
                    self.read_tcl_registers()
                else:
                    # 对于同飞等其他协议，使用连续读取策略
                    self.read_continuous_registers()

        except Exception as e:
            self.status_msg.set(f"读取寄存器错误: {str(e)}")

    def read_tcl_registers(self):
        """读取TCL协议的寄存器 - 分组读取策略"""
        try:
            # 获取所有只读寄存器地址
            ro_registers = self.current_protocol.get("registers", {}).get("read_only", [])

            # 将寄存器按地址范围分组
            groups = self.group_registers(ro_registers)

            # 记录分组信息
            self.tcl_read_groups = groups
            self.current_tcl_group_index = 0

            # 开始读取第一组
            if groups:
                self.read_tcl_group(0)
            else:
                self.status_msg.set("没有找到只读寄存器")

        except Exception as e:
            self.status_msg.set(f"读取TCL寄存器错误: {str(e)}")

    def group_registers(self, registers):
        """将寄存器按地址范围分组"""
        if not registers:
            return []

        # 提取地址并排序
        addresses = sorted([reg.get("address") for reg in registers if reg.get("address") is not None])

        # 分组策略：将连续的地址分为一组
        groups = []
        current_group = []

        for i, addr in enumerate(addresses):
            if not current_group:
                current_group.append(addr)
            elif addr == current_group[-1] + 1:
                current_group.append(addr)
            else:
                # 当前组结束，开始新组
                groups.append({
                    "start": current_group[0],
                    "count": len(current_group),
                    "registers": current_group.copy()
                })
                current_group = [addr]

        # 添加最后一组
        if current_group:
            groups.append({
                "start": current_group[0],
                "count": len(current_group),
                "registers": current_group.copy()
            })

        return groups

    def read_tcl_group(self, group_index):
        """读取TCL协议的指定分组"""
        if group_index >= len(self.tcl_read_groups):
            # 所有分组读取完成，开始读取读写寄存器
            self.read_tcl_rw_registers()
            return

        group = self.tcl_read_groups[group_index]

        # 生成读取命令
        hex_command = self.protocol_parser.format_hex_command(
            "READ_MULTIPLE_REGISTERS", group["start"], group["count"]
        )

        if hex_command:
            # 记录当前分组信息
            self.current_tcl_group = group
            self.current_tcl_group_index = group_index

            # 发送HEX命令
            self.serial_manager.serial_port.write(hex_command)

            # 记录发送的HEX数据
            if hasattr(self, 'log_communication'):
                self.log_communication("Tx", hex_command)

            # 等待一段时间让设备响应
            self.root.after(100, lambda: self.process_tcl_group_response(group_index))
        else:
            self.status_msg.set("无法创建读取命令")

    def process_tcl_group_response(self, group_index):
        """处理TCL协议分组响应"""
        try:
            # 读取数据
            data = self.serial_manager.read_data()
            if data:
                # 解析HEX数据
                parsed_data = self.protocol_parser.parse(data)

                # 更新寄存器值
                group = self.tcl_read_groups[group_index]
                for addr in group["registers"]:
                    if str(addr) in parsed_data:
                        # 查找寄存器配置
                        reg_config = None
                        for reg in self.current_protocol.get("registers", {}).get("read_only", []):
                            if reg.get("address") == addr:
                                reg_config = reg
                                break

                        if reg_config:
                            # 获取原始值
                            raw_value = parsed_data[str(addr)]

                            # 获取数据类型和缩放因子
                            data_type = reg_config.get("data_type", "uint16")
                            scale = reg_config.get("scale", 1)

                            # 解析值（考虑数据类型和缩放因子）
                            scaled_value = self.protocol_parser.parse_register_value(raw_value, data_type, scale)

                            # 更新表格显示
                            self.update_register_value(self.ro_table, str(addr), scaled_value)

                # 记录时间戳
                self.timestamps.append(time.time())

                # 记录数据
                if self.is_logging:
                    self.data_logger.log_data(parsed_data)

                # 读取下一组
                self.current_tcl_group_index += 1
                self.read_tcl_group(self.current_tcl_group_index)
            else:
                self.status_msg.set("未收到设备响应")

        except Exception as e:
            self.status_msg.set(f"处理TCL分组响应错误: {str(e)}")

    def read_tcl_rw_registers(self):
        """读取TCL协议的读写寄存器"""
        try:
            # 获取所有读写寄存器地址
            rw_registers = self.current_protocol.get("registers", {}).get("read_write", [])

            # 将寄存器按地址范围分组
            groups = self.group_registers(rw_registers)

            # 记录分组信息
            self.tcl_rw_read_groups = groups
            self.current_tcl_rw_group_index = 0

            # 开始读取第一组
            if groups:
                self.read_tcl_rw_group(0)
            else:
                self.status_msg.set("已读取所有寄存器")

        except Exception as e:
            self.status_msg.set(f"读取TCL读写寄存器错误: {str(e)}")

    def read_tcl_rw_group(self, group_index):
        """读取TCL协议的指定读写寄存器分组"""
        if group_index >= len(self.tcl_rw_read_groups):
            # 所有分组读取完成
            self.status_msg.set("已读取所有寄存器")
            return

        group = self.tcl_rw_read_groups[group_index]

        # 生成读取命令
        hex_command = self.protocol_parser.format_hex_command(
            "READ_MULTIPLE_REGISTERS", group["start"], group["count"]
        )

        if hex_command:
            # 记录当前分组信息
            self.current_tcl_rw_group = group
            self.current_tcl_rw_group_index = group_index

            # 发送HEX命令
            self.serial_manager.serial_port.write(hex_command)

            # 记录发送的HEX数据
            if hasattr(self, 'log_communication'):
                self.log_communication("Tx", hex_command)

            # 等待一段时间让设备响应
            self.root.after(100, lambda: self.process_tcl_rw_group_response(group_index))
        else:
            self.status_msg.set("无法创建读取命令")

    def process_tcl_rw_group_response(self, group_index):
        """处理TCL协议读写寄存器分组响应"""
        try:
            # 读取数据
            data = self.serial_manager.read_data()
            if data:
                # 解析HEX数据
                parsed_data = self.protocol_parser.parse(data)

                # 更新寄存器值
                group = self.tcl_rw_read_groups[group_index]
                for addr in group["registers"]:
                    if str(addr) in parsed_data:
                        # 查找寄存器配置
                        reg_config = None
                        for reg in self.current_protocol.get("registers", {}).get("read_write", []):
                            if reg.get("address") == addr:
                                reg_config = reg
                                break

                        if reg_config:
                            # 获取原始值
                            raw_value = parsed_data[str(addr)]

                            # 获取数据类型和缩放因子
                            data_type = reg_config.get("data_type", "uint16")
                            scale = reg_config.get("scale", 1)

                            # 解析值（考虑数据类型和缩放因子）
                            scaled_value = self.protocol_parser.parse_register_value(raw_value, data_type, scale)

                            # 更新表格显示
                            self.update_register_value(self.rw_table, str(addr), scaled_value)

                # 记录时间戳
                self.timestamps.append(time.time())

                # 记录数据
                if self.is_logging:
                    self.data_logger.log_data(parsed_data)

                # 读取下一组
                self.current_tcl_rw_group_index += 1
                self.read_tcl_rw_group(self.current_tcl_rw_group_index)
            else:
                self.status_msg.set("未收到设备响应")

        except Exception as e:
            self.status_msg.set(f"处理TCL读写分组响应错误: {str(e)}")

    def read_continuous_registers(self):
        """读取连续地址的寄存器（适用于同飞等协议）"""
        try:
            # 获取所有只读寄存器地址
            ro_registers = self.current_protocol.get("registers", {}).get("read_only", [])

            # 计算只读寄存器的地址范围
            if ro_registers:
                ro_addresses = [reg.get("address") for reg in ro_registers if reg.get("address") is not None]
                if ro_addresses:
                    start_address = min(ro_addresses)
                    end_address = max(ro_addresses)
                    count = end_address - start_address + 1

                    # 生成读取命令
                    hex_command = self.protocol_parser.format_hex_command(
                        "READ_MULTIPLE_REGISTERS", start_address, count
                    )

                    if hex_command:
                        # 记录请求信息
                        self.last_ro_request = {
                            "start_address": start_address,
                            "count": count,
                            "timestamp": time.time()
                        }

                        # 发送HEX命令
                        self.serial_manager.serial_port.write(hex_command)

                        # 记录发送的HEX数据
                        if hasattr(self, 'log_communication'):
                            self.log_communication("Tx", hex_command)

                        # 等待一段时间让设备响应
                        self.root.after(100, self.process_ro_register_response)
                    else:
                        self.status_msg.set("无法创建读取命令")
                else:
                    self.status_msg.set("没有找到只读寄存器地址")
            else:
                self.status_msg.set("协议中没有定义只读寄存器")

        except Exception as e:
            self.status_msg.set(f"读取连续寄存器错误: {str(e)}")

    def process_ro_register_response(self):
        """处理只读寄存器响应"""
        try:
            # 读取数据
            data = self.serial_manager.read_data()
            if data and hasattr(self, 'last_ro_request'):
                # 解析HEX数据
                parsed_data = self.protocol_parser.parse(data)

                # 更新只读寄存器值
                if self.current_protocol:
                    registers = self.current_protocol.get("registers", {})

                    # 更新只读寄存器
                    for reg in registers.get("read_only", []):
                        address = str(reg.get("address"))
                        if address in parsed_data:
                            # 获取原始值
                            raw_value = parsed_data[address]

                            # 获取数据类型和缩放因子
                            data_type = reg.get("data_type", "uint16")
                            scale = reg.get("scale", 1)

                            # 解析值（考虑数据类型和缩放因子）
                            scaled_value = self.protocol_parser.parse_register_value(raw_value, data_type, scale)

                            # 更新表格显示
                            self.update_register_value(self.ro_table, address, scaled_value)

                    # 记录时间戳
                    self.timestamps.append(time.time())

                    # 记录数据
                    if self.is_logging:
                        self.data_logger.log_data(parsed_data)

                    self.status_msg.set("已读取只读寄存器")

                    # 读取读写寄存器
                    self.read_rw_registers()
                else:
                    self.status_msg.set("未加载协议配置，无法解析数据")
            else:
                self.status_msg.set("未收到设备响应")

        except Exception as e:
            self.status_msg.set(f"处理只读寄存器响应错误: {str(e)}")

    def read_rw_registers(self):
        """读取读写寄存器的值"""
        try:
            if self.current_protocol:
                # 获取所有读写寄存器地址
                rw_registers = self.current_protocol.get("registers", {}).get("read_write", [])

                # 计算读写寄存器的地址范围
                if rw_registers:
                    rw_addresses = [reg.get("address") for reg in rw_registers if reg.get("address") is not None]
                    if rw_addresses:
                        start_address = min(rw_addresses)
                        end_address = max(rw_addresses)
                        count = end_address - start_address + 1

                        # 生成读取命令
                        hex_command = self.protocol_parser.format_hex_command(
                            "READ_MULTIPLE_REGISTERS", start_address, count
                        )

                        if hex_command:
                            # 记录请求信息
                            self.last_rw_request = {
                                "start_address": start_address,
                                "count": count,
                                "timestamp": time.time()
                            }

                            # 发送HEX命令
                            self.serial_manager.serial_port.write(hex_command)

                            # 记录发送的HEX数据
                            if hasattr(self, 'log_communication'):
                                self.log_communication("Tx", hex_command)

                            # 等待一段时间让设备响应
                            self.root.after(100, self.process_rw_register_response)
                        else:
                            self.status_msg.set("无法创建读写寄存器读取命令")
                    else:
                        self.status_msg.set("没有找到读写寄存器地址")
                else:
                    # 没有读写寄存器，直接完成
                    self.status_msg.set("已读取所有寄存器")
            else:
                self.status_msg.set("未加载协议配置")

        except Exception as e:
            self.status_msg.set(f"读取读写寄存器错误: {str(e)}")

    def process_rw_register_response(self):
        """处理读写寄存器响应"""
        try:
            # 读取数据
            data = self.serial_manager.read_data()
            if data and hasattr(self, 'last_rw_request'):
                # 解析HEX数据
                parsed_data = self.protocol_parser.parse(data)

                # 更新读写寄存器值
                if self.current_protocol:
                    registers = self.current_protocol.get("registers", {})

                    # 更新读写寄存器
                    for reg in registers.get("read_write", []):
                        address = str(reg.get("address"))
                        if address in parsed_data:
                            # 获取原始值
                            raw_value = parsed_data[address]

                            # 获取数据类型和缩放因子
                            data_type = reg.get("data_type", "uint16")
                            scale = reg.get("scale", 1)

                            # 解析值（考虑数据类型和缩放因子）
                            scaled_value = self.protocol_parser.parse_register_value(raw_value, data_type, scale)

                            # 更新表格显示
                            self.update_register_value(self.rw_table, address, scaled_value)

                    # 记录时间戳
                    self.timestamps.append(time.time())

                    # 记录数据
                    if self.is_logging:
                        self.data_logger.log_data(parsed_data)

                    self.status_msg.set("已读取所有寄存器")
                else:
                    self.status_msg.set("未加载协议配置，无法解析数据")
            else:
                self.status_msg.set("未收到设备响应")

        except Exception as e:
            self.status_msg.set(f"处理读写寄存器响应错误: {str(e)}")

    def process_register_response(self):
        """处理读取寄存器的响应"""
        try:
            # 读取数据
            data = self.serial_manager.read_data()
            if data:
                # 解析HEX数据
                parsed_data = self.protocol_parser.parse(data)

                # 更新寄存器值
                if self.current_protocol:
                    registers = self.current_protocol.get("registers", {})

                    # 更新只读寄存器
                    for reg in registers.get("read_only", []):
                        address = str(reg.get("address"))
                        if address in parsed_data:
                            # 获取原始值
                            raw_value = parsed_data[address]

                            # 获取数据类型和缩放因子
                            data_type = reg.get("data_type", "uint16")
                            scale = reg.get("scale", 1)

                            # 解析值（考虑数据类型和缩放因子）
                            scaled_value = self.protocol_parser.parse_register_value(raw_value, data_type, scale)

                            # 更新表格显示
                            self.update_register_value(self.ro_table, address, scaled_value)

                    # 更新读写寄存器
                    for reg in registers.get("read_write", []):
                        address = str(reg.get("address"))
                        if address in parsed_data:
                            # 获取原始值
                            raw_value = parsed_data[address]

                            # 获取数据类型和缩放因子
                            data_type = reg.get("data_type", "uint16")
                            scale = reg.get("scale", 1)

                            # 解析值（考虑数据类型和缩放因子）
                            scaled_value = self.protocol_parser.parse_register_value(raw_value, data_type, scale)

                            # 更新表格显示
                            self.update_register_value(self.rw_table, address, scaled_value)

                    # 记录时间戳
                    self.timestamps.append(time.time())

                    # 记录数据
                    if self.is_logging:
                        self.data_logger.log_data(parsed_data)

                    self.status_msg.set("已读取所有寄存器")
                else:
                    self.status_msg.set("未加载协议配置，无法解析数据")
            else:
                self.status_msg.set("未收到设备响应")

        except Exception as e:
            self.status_msg.set(f"处理寄存器响应错误: {str(e)}")

    def update_serial_ports(self):
        """更新可用串口列表"""
        ports = self.serial_manager.get_available_ports()
        self.port_combo['values'] = ports
        if ports and self.port_var.get() not in ports:
            self.port_var.set(ports[0])

    def update_register_value(self, table, address, value):
        """更新寄存器值并添加时间戳"""
        from datetime import datetime
        timestamp = datetime.now().strftime("%Y.%m.%d %H:%M:%S.%f")[:-3]  # 格式: 2025.09.03 10:55:33.294

        for item in table.get_children():
            current_values = list(table.item(item, "values"))
            if current_values[0] == address:  # 地址列
                # 更新值和时间戳
                current_values[2] = value  # value列
                current_values[6] = timestamp  # timestamp列
                table.item(item, values=tuple(current_values))
                break

        # 更新内部存储
        self.register_values[address] = value

    def toggle_connection(self):
        """切换连接状态"""
        if self.is_connected:
            self.disconnect()
        else:
            self.connect()

    def connect(self):
        """连接串口"""
        port = self.port_var.get()
        if not port:
            messagebox.showerror("错误", "请选择串口")
            return

        baudrate = int(self.baudrate_var.get())
        bytesize = int(self.databits_var.get())
        stopbits = float(self.stopbits_var.get())
        parity = self.parity_var.get()

        try:
            self.serial_manager.connect(port, baudrate, bytesize, stopbits, parity)
            self.is_connected = True
            self.connect_btn.config(text="断开")
            self.status_var.set("已连接")
            self.status_msg.set(f"已连接到 {port}")

            # 保存配置
            self.save_config()

        except Exception as e:
            messagebox.showerror("连接错误", f"无法连接串口: {str(e)}")

    def disconnect(self):
        """断开串口连接"""
        self.serial_manager.disconnect()
        self.is_connected = False
        self.connect_btn.config(text="连接")
        self.status_var.set("未连接")
        self.status_msg.set("已断开连接")

        # 如果正在自动刷新，停止自动刷新
        if self.is_auto_refresh:
            self.stop_auto_refresh()

    def toggle_logging(self):
        """切换数据记录状态"""
        if self.is_logging:
            self.stop_logging()
        else:
            self.start_logging()

    def start_logging(self):
        """开始记录数据"""
        filename = filedialog.asksaveasfilename(
            defaultextension=".csv",
            filetypes=[("CSV files", "*.csv"), ("All files", "*.*")]
        )
        if filename:
            self.data_logger.start_logging(filename)
            self.is_logging = True
            self.start_log_btn.config(text="停止记录")
            self.status_msg.set(f"数据记录已开始: {filename}")

    def stop_logging(self):
        """停止记录数据"""
        self.data_logger.stop_logging()
        self.is_logging = False
        self.start_log_btn.config(text="开始记录")
        self.status_msg.set("数据记录已停止")

    def save_config(self):
        """保存配置"""
        config = {
            'serial': {
                'port': self.port_var.get(),
                'baudrate': self.baudrate_var.get(),
                'databits': self.databits_var.get(),
                'stopbits': self.stopbits_var.get(),
                'parity': self.parity_var.get()
            },
            'protocol': {
                'current': self.protocol_var.get()
            }
        }
        self.config_manager.save_config(config)

    def on_closing(self):
        """程序关闭时的处理"""
        if self.is_connected:
            self.disconnect()
        if self.is_logging:
            self.stop_logging()
        if self.is_auto_refresh:
            self.stop_auto_refresh()
        self.root.destroy()